<script setup lang="ts">
import { ElMessage } from "element-plus";
import type { PageApi, PageView } from "./api-scan-local";
import { scanApiFromPages } from "./api-scan";
import { YiAction, YiTable } from "@uublue/yimi-element-plus";
import { mapRecursively } from "@/utils/array-recursion";
import axiosInst from "@/utils/request";

const applicationNameOptions: Ref<Record<string, any>[]> = ref([]);
const menuItemGroupOptions: Ref<Record<string, any>[]> = ref([]);
const syncPageApiMenuGroup: Ref<string> = ref("local");
const syncPageApiData: Ref<PageApi[]> = ref([]);

axiosInst.request(listServices).then((res) => {
  applicationNameOptions.value = mapRecursively(res.data as any[], (item) => {
    return {
      value: item.code,
      label: item.label,
      children: item.children,
    };
  });
});

axiosInst.request(getMenuGroups).then((res) => {
  menuItemGroupOptions.value = mapRecursively(res.data as any[], (item) => {
    return {
      value: item.id,
      label: item.label,
      code: item.code,
      children: item.children,
    };
  });
});

async function resolvePageApiViews(menuGroup: string): Promise<{
  apis: PageApi[];
  pageApiViews: PageView[];
}> {
  return new Promise<{
    apis: PageApi[];
    pageApiViews: PageView[];
  }>((resolve, reject) => {
    scanApiFromPages(menuGroup)
      .then((pageApiViews) => {
        const apis = getApisFromPageApiViews(pageApiViews);
        resolve({ apis, pageApiViews });
      })
      .catch((error) => {
        resolve({ apis: [], pageApiViews: [] });
        if (error.type == "NoArgsRunApiError") {
          ElMessage({
            type: "error",
            showClose: true,
            duration: 10000,
            message: `页面接口扫描出错，请确保所有函数类型的api定义可以无参运行:${error.error.message}`,
          });
        }
      });
  });
}

// methods
function getApisFromPageApiViews(pageApiViews: PageView[]) {
  const apis: PageApi[] = [];
  pageApiViews.forEach((page) => {
    if (Array.isArray(page.apis)) {
      page.apis.forEach((api) => {
        const _api: PageApi = {
          antPattern: api.antPattern,
          method: api.method,
        };
        _api.pagePath = page.path;
        apis.push(_api);
      });
    }
  });
  return apis;
}
</script>

<!-- 定义api -->
<script lang="ts">
import apiApis from "@/apis/system/api";
import dictApis from "@/apis/system/dict";
import menuApis from "@/apis/system/menu";
import ApiDisplay from "./api-display.vue";
import SecurityDisplay from "./security-display.vue";
import { ref, type Ref } from "vue";

const { syncPageApis, queryPageApis } = apiApis;
const { listServices } = dictApis;
const { getMenuGroups } = menuApis;
export default {
  name: "ApiView",
  apis: {
    listServices,
    syncPageApis,
    queryPageApis,
    getMenuGroups,
  },
  subViews: [ApiDisplay, SecurityDisplay],
};
</script>

<template>
  <div class="app-container">
    <yi-table
      ref="pageApiTable"
      :api="queryPageApis"
      :columns="[
        {
          label: '接口名称',
          prop: 'name',
          slot: 'name',
        },
        {
          label: '所需权限',
          prop: 'permissions',
          slot: 'permissions',
        },
        {
          label: '所需角色',
          prop: 'roles',
          slot: 'roles',
        },
        {
          label: '类名',
          prop: 'className',
          width: 550,
        },
        {
          label: '方法名',
          prop: 'methodName',
        },
        {
          label: '所在页面',
          prop: 'pageApis',
          slot: 'pageApis',
        },
      ]"
    >
      <template #conditions="{ model, refresh }">
        <el-form :model="model" inline size="small">
          <el-form-item label="接口名称">
            <el-input
              v-model="model.name"
              placeholder="请输入接口名称"
            ></el-input>
          </el-form-item>
          <el-form-item label="接口服务">
            <el-select
              clearable
              v-model="model.applicationName"
              size="small"
              style="width: 240px"
              @change="refresh"
            >
              <el-option
                v-for="(item, index) in applicationNameOptions"
                :key="index"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="菜单组">
            <el-select
              v-model="model.pageGroupId"
              placeholder="选择菜单组"
              clearable
              size="small"
              style="width: 240px"
              @change="refresh"
            >
              <el-option
                v-for="(item, index) in menuItemGroupOptions"
                :key="index"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="refresh()">查询</el-button>
          </el-form-item>
        </el-form>
      </template>
      <template #actions="{ refresh }">
        <yi-action
          :api="syncPageApis"
          text="同步页面接口"
          type="danger"
          size="small"
          :plain="true"
          icon="el-icon-upload-filled"
          modal-title="页面与操作"
          dialog-width="80%"
          :on-open="
            ({ resolve }) => {
              resolvePageApiViews(syncPageApiMenuGroup).then(
                ({ apis, pageApiViews }) => {
                  syncPageApiData = apis;
                  resolve(undefined, { pageApiViews });
                },
              );
            }
          "
          :on-submit="
            ({ model }, request, close) => {
              request({
                data: syncPageApiData,
                params: {
                  menuGroup: syncPageApiMenuGroup,
                },
              }).then(() => {
                close();
              });
            }
          "
          @on-submit-success="refresh"
        >
          <template #default="{ context, setContext }">
            <yi-table
              row-key="path"
              :columns="[
                {
                  label: '页面路径',
                  prop: 'path',
                },
                {
                  label: '标题',
                  align: 'center',
                  prop: 'title',
                },
                {
                  label: '权限标识',
                  align: 'center',
                  prop: 'permission',
                },
                {
                  label: '接口',
                  headerAlign: 'center',
                  prop: 'apis',
                  slot: 'apis',
                },
              ]"
              :tools="[]"
              max-height="650px"
              :border="true"
              :paged="false"
              default-expand-all
              :data="context.pageApiViews"
            >
              <template #actions>
                <el-select
                  v-model="syncPageApiMenuGroup"
                  placeholder="选择菜单组"
                  clearable
                  size="small"
                  style="width: 240px"
                  @change="
                    (menuGroup: string) => {
                      resolvePageApiViews(menuGroup).then(
                        ({ apis, pageApiViews }) => {
                          syncPageApiData = apis;
                          setContext({ pageApiViews });
                        },
                      );
                    }
                  "
                >
                  <el-option
                    v-for="(item, index) in menuItemGroupOptions"
                    :key="index"
                    :label="item.label"
                    :value="item.code"
                  />
                </el-select>
              </template>
              <template #apis="{ row }">
                <ul v-if="Array.isArray(row.apis)">
                  <li v-for="(api, index) in row.apis" :key="index">
                    <api-display :api="api" />
                  </li>
                </ul>
              </template>
            </yi-table>
          </template>
        </yi-action>
      </template>
      <template #name="{ row, value }">
        <span v-if="value">{{ value }}</span>
        <api-display
          v-else
          order-swap
          :api="{
            antPattern: row.antPattern,
            method: row.method,
          }"
        />
      </template>
      <template #permissions="{ row }">
        <security-display :codes="row.permissions" />
      </template>
      <template #roles="{ row }">
        <security-display :codes="row.roles" />
      </template>
      <template #pageApis="{ row }">
        <el-tag
          v-for="(pageApi, index) in row.pageApis"
          :key="index"
          size="default"
          type="info"
          >{{ pageApi.pagePath }}</el-tag
        >
      </template>
    </yi-table>
  </div>
</template>

<style lang="scss" scoped></style>
